import moment from 'moment';
import { getRateList, getKrwRateList } from '@/utils/api';
import WS from '@/utils/ws';
import types from '../types';

const state = {
    coin: 'BTC',
    upbitWs: null,
    upbitData: {},
    binanceWs: null,
    binanceData: {},
    rateTimer: {},
    krwRateObj: {},
    tickerWs: null,
    tickerData: [],
    chatWs: null,
    chatTotal: 0,
    chatList: [],
    usdRate: '',
    usdtRate: '',
};

const getter = {
    krwRateList: (state) => Object.keys(state.krwRateObj).map(item => ({
        time: new Date(moment(item)).getTime(),
        rate: state.krwRateObj[item],
    })).sort((a, b) => b.time - a.time),
    krwRate: (state, getters) => getters.krwRateList?.[0]?.rate,
    diffData: (state) => {
        const usdt = state.upbitData.usdt - state.binanceData.usdt;
        const krw = state.upbitData.krw - state.binanceData.krw;
        const rate = (usdt / state.binanceData.usdt) * 100;

        return {
            usdt,
            krw,
            rate,
        };
    },
};

const mutations = {
    // 设置主题
    [types.SET_COIN](state, data) {
        state.coin = data;
    },
    [types.SET_RATE](state, data) {
        state.krwRateObj = data;
    },
};

const actions = {
    async [types.GET_KRW_RATE]({ commit }) {
        const res = await getKrwRateList();
        const { code, data } = res;

        if (code === 200 && data) {
            commit(types.SET_RATE, { ...data });
        }
    },
    async [types.GET_RATE]({ commit, state }) {
        const res = await getRateList();
        const { code, data } = res;

        if (code === 200 && data) {
            const usdt = data.find(item => item.symbol === 'usdt_krw');
            const usd = data.find(item => item.symbol === 'usd_krw');
            state.usdtRate = usdt?.rate;
            state.usdRate = usd?.rate;
        }
    },
    [types.INIT_WS]({ dispatch, state }) {
        if (!state.upbitWs && !state.binanceWs) {
            state.upbitWs = new WS('wss://api.upbit.com/websocket/v1');
            state.binanceWs = new WS('wss://data-stream.binance.vision/ws');
            dispatch(types.SUB_TICKER);
        }
    },
    [types.CLOSE_WS]({ state }) {
        state.coin = 'BTC';

        if (state.upbitWs) {
            state.upbitWs.close();
            state.upbitData = {};
        }

        if (state.binanceWs) {
            state.binanceWs.close();
            state.binanceData = {};
        }
    },
    async [types.SET_TIMEOUT_RATE]({ dispatch, state }, time = 1000 * 60) {
        if (state.rateTimer) {
            clearTimeout(state.rateTimer);
        }

        await dispatch(types.GET_RATE);

        state.rateTimer = setTimeout(() => {
            dispatch(types.SET_TIMEOUT_RATE, time);
        }, time);
    },
    [types.CLEAR_TIMEOUT_RATE]({ commit, state }) {
        clearTimeout(state.rateTimer);
        state.rateTimer = null;
        commit(types.SET_RATE, {});
    },
    [types.SUB_TICKER]({ state, getters }) {
        const now = new Date().getTime();
        const symbol = `${state.coin}usdt`.toLowerCase();
        state.upbitWs.sub([
            {
                ticket: `${state.coin}_${now}`,
            },
            {
                type: 'ticker',
                codes: [
                    `KRW-${state.coin}`.toUpperCase(),
                ],
            },
            {
                format: 'SIMPLE',
            },
        ], (data) => {
            state.upbitData = {
                krw: data.tp,
                usdt: data.tp / getters.krwRate,
            };
        });
        state.binanceWs.sub({
            method: 'SUBSCRIBE',
            params: [
                `${symbol}@miniTicker`,
            ],
            id: now,
        }, (data) => {
            state.binanceData = {
                krw: data.c * getters.krwRate,
                usdt: data.c,
            };
        });
    },
    [types.UN_SUB_TICKER]({ state }, old) {
        const now = new Date().getTime();
        const symbol = `${old}usdt`.toLowerCase();
        state.binanceData = {};
        state.upbitData = {};
        return new Promise(resolve => {
            state.binanceWs.sub({
                method: 'UNSUBSCRIBE',
                params: [
                    `${symbol}@miniTicker`,
                ],
                id: now,
            }, (data) => {
                resolve(!!data);
            });
        });
    },
    [types.INIT_TICKER_WS]({ state }) {
        if (!state.tickerWs) {
            state.tickerWs = new WS('wss://api.bitunu.com/ws/ticker');
            state.tickerWs.cb = (data) => {
                if (data) {
                    state.tickerData = data.map((item, index) => ({
                        ...item,
                        upbitClosePrice: Number(item?.upbit.closePrice),
                        upbitVolume: Number(item?.upbit.closePrice) * Number(item?.upbit.volume),
                    }));
                }
            };
        }
    },
    [types.INIT_CHAT_WS]({ state, rootState }, cb) {
        if (!state.chatWs) {
            state.chatWs = new WS(`wss://api.bitunu.com/ws/chat-group?ws_user_id=${rootState.common.fingerprint}`);
            state.chatWs.cb = (res) => {
                const { data, type } = res;

                if (type === 'msg' || type === 'warn') {
                    if (data.time && new Date().getTime() - data.time > 30 * 1000 * 60) {
                        data.timeStr = moment(data.time).fromNow();
                    }

                    state.chatList.push({
                        ...data,
                        message: data.message.replace(/\\n/, '<br>'),
                        type,
                    });

                    if (cb) {
                        nextTick(() => {
                            cb();
                        });
                    }
                } else if (type === 'login') {
                    state.chatTotal = data.total;
                }
            };
            state.chatWs.reload = () => {
                window.location.reload();
            };
        }
    },
};

export default {
    state,
    getters: getter,
    mutations,
    actions,
};
